#include <iostream>
#include <fstream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <chrono>

#define PORT 8080
#define BUFFER_SIZE 1024

int main(int argc, char const *argv[]) {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE] = {0};
    const char* filename = "large_file.bin";
    
    if (argc > 1) {
        filename = argv[1];
    }
    
    // 创建套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        std::cout << "\nSocket creation error\n";
        return -1;
    }
    
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    
    // 将IPv4地址从点分十进制转换为二进制形式
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        std::cout << "\nInvalid address/ Address not supported\n";
        return -1;
    }
    
    // 连接服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        std::cout << "\nConnection Failed\n";
        return -1;
    }
    
    std::ifstream file(filename, std::ios::binary);
    if (!file) {
        std::cout << "\nFile open failed\n";
        return -1;
    }
    
    auto start_time = std::chrono::high_resolution_clock::now();
    size_t total_bytes = 0;
    
    // 发送文件
    while (!file.eof()) {
        file.read(buffer, BUFFER_SIZE);
        size_t bytes_to_send = file.gcount();
        if (bytes_to_send > 0) {
            send(sock, buffer, bytes_to_send, 0);
            total_bytes += bytes_to_send;
        }
    }
    
    auto end_time = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time).count();
    
    file.close();
    close(sock);
    
    std::cout << "TCP File sent successfully: " << total_bytes << " bytes in " 
              << duration << " seconds" << std::endl;
    if (duration > 0) {
        std::cout << "Effective transfer rate: " 
                  << (total_bytes / (1024.0 * 1024.0)) / duration << " MB/s" << std::endl;
    }
    
    return 0;
}    